Tests / Build Scripts: Configure PHPStan level 0#10419
Tests / Build Scripts: Configure PHPStan level 0#10419justlevine wants to merge 44 commits intoWordPress:trunkfrom
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
86c9442 to
0308f9e
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces PHPStan level 0 static analysis configuration to WordPress Core, establishing a foundation for catching code errors without execution. The implementation includes PHPStan configuration files, bootstrap scripts, documentation, GitHub workflows for CI integration, and inline code annotations to suppress legitimate PHPStan warnings.
Changes:
- Added PHPStan level 0 configuration with baseline support for legacy code
- Added PHPStan annotations to source files to document legitimate suppressions
- Integrated PHPStan into CI/CD via GitHub workflows and npm/composer scripts
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| phpstan.neon.dist | Main PHPStan configuration with level 0 rules and baseline inclusion |
| tests/phpstan/base.neon | Base configuration defining paths, exclusions, and codebase-specific settings |
| tests/phpstan/baseline.php | Empty baseline file for future tech debt tracking |
| tests/phpstan/bootstrap.php | Defines WordPress constants for PHPStan discovery |
| tests/phpstan/README.md | Documentation for running and configuring PHPStan |
| src/wp-includes/template.php | Added PHPStan annotations and removed obsolete comment |
| src/wp-includes/style-engine/class-wp-style-engine-css-rules-store.php | Added @phpstan-consistent-constructor annotation |
| src/wp-includes/media.php | Added annotation for PHP8+ GdImage class |
| src/wp-includes/functions.php | Added enhanced return type documentation for wp_die() |
| src/wp-includes/customize/*.php | Added @return documentation for overridden update() methods |
| src/wp-includes/class-wp-theme-json.php | Added null return value to match documented return type |
| src/wp-includes/class-wp-scripts.php | Removed obsolete PHPStan suppression comment |
| src/wp-admin/press-this.php | Added PHPStan annotations for plugin file includes |
| src/wp-admin/includes/class-wp-filesystem-ssh2.php | Added phpstan-ignore-next-line for unimplemented method |
| composer.json | Added phpstan/phpstan dependency and analyse script |
| package.json | Added test:php:stan npm script |
| phpcs.xml.dist | Excluded PHPStan files from coding standards checks |
| .gitignore | Added phpstan.neon to ignore list for local overrides |
| .github/workflows/php-static-analysis.yml | Main workflow for running PHPStan on pushes and PRs |
| .github/workflows/reusable-php-static-analysis.yml | Reusable workflow for PHPStan execution |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "squizlabs/php_codesniffer": "3.13.5", | ||
| "wp-coding-standards/wpcs": "~3.3.0", | ||
| "phpcompatibility/phpcompatibility-wp": "~2.1.3", | ||
| "phpstan/phpstan": "~2.1.33", |
Copilot
AI
Feb 12, 2026
•
There was a problem hiding this comment.
The version constraint "~2.1.33" is very specific and may cause issues. The tilde operator (~) for a three-part version like 2.1.33 means ">=2.1.33 <2.2.0". This constraint locks to a specific patch version which may not exist or may prevent receiving important bug fixes. Consider using "^2.1" (which means ">=2.1.0 <3.0.0") or "~2.1.0" (which means ">=2.1.0 <2.2.0") instead to allow flexibility for patch updates while staying within the same minor version
| "phpstan/phpstan": "~2.1.33", | |
| "phpstan/phpstan": "~2.1.0", |
There was a problem hiding this comment.
@westonruter what are your thoughts on this one?
I definitely think we should pin at the version we commit, but I wouldn't want to Semver because contextually "nonbreaking enhancements" are breaking from an implementation POV if they create a new quality gate.
There was a problem hiding this comment.
That makes sense to me. So switching to ~2.1.0 would keep it at 2.1.x. This seems necessary because there is no composer.lock, which actually is curious since we package-lock.json. If we had a composer.lock then we'd be free to use ^2.1. But I suppose can't use it because of the different versions of PHP which may end up getting used when doing composer install.
So yeah, I guess go with ~2.1.0 and not ^2.1. When PHPStan 2.2 comes out, we'll have to manually upgrade.
There was a problem hiding this comment.
Depending on when we merge, there might be some value to pinning a minimum patch release too e.g. phpstan/phpstan#8438 (comment) . Leaving this for now, and might even bump it if this PR lingers. Keeping the issue open as a reminder to drop this as low as we think is worthwhile before we merge.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
src/wp-includes/customize/class-wp-customize-background-image-setting.php
Outdated
Show resolved
Hide resolved
src/wp-includes/customize/class-wp-customize-background-image-setting.php
Show resolved
Hide resolved
src/wp-includes/customize/class-wp-customize-filter-setting.php
Outdated
Show resolved
Hide resolved
src/wp-includes/customize/class-wp-customize-filter-setting.php
Outdated
Show resolved
Hide resolved
src/wp-includes/customize/class-wp-customize-header-image-setting.php
Outdated
Show resolved
Hide resolved
|
In |
@westonruter can you run it with (Also confirming that you're using the vanilla |
|
Actually, I was using a local wordpress-develop/tests/phpstan/base.neon Lines 62 to 63 in 75c8c54 If I change it to: paths:
- ../../src/wp-admin
- ../../src/wp-includesThen it works, aside from two errors being found: What appears to be the issue is that I use my Nevertheless, the change I made is not ideal because then it doesn't check the PHP files in the root of |
| # These files are sourced by wordpress/gutenberg in `tools/release/sync-stable-blocks.js`. | ||
| - ../../src/wp-includes/blocks |
There was a problem hiding this comment.
I suppose then this would necessitate adding PHPStan to Gutenberg to do the necessary checks?
There was a problem hiding this comment.
WordPress/gutenberg#66598 but it's been gathering dust for a while.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 29 out of 30 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - 'composer.*' | ||
| # These files configure PHPStan. Changes could affect the outcome. | ||
| - 'phpstan.neon.dist' | ||
| - 'tests/phpstan/base.neon' |
There was a problem hiding this comment.
The workflow paths configuration should also include 'tests/phpstan/bootstrap.php' as changes to this file could affect PHPStan analysis by modifying constant definitions used during static analysis.
| - 'tests/phpstan/base.neon' | |
| - 'tests/phpstan/base.neon' | |
| - 'tests/phpstan/bootstrap.php' |
There was a problem hiding this comment.
Well, I committed this but it actually isn't needed because **.php is already included.
Gemini's reviewThis is a comprehensive review of the changes proposed for integrating PHPStan into WordPress core. The review focuses on technical accuracy, adherence to WordPress coding standards, PHP 7.4 compatibility, and overall architectural consistency. GitHub Workflows
General Configuration
Core PHP Changes
Theme Changes
Documentation
Summary of Nit-picks & Concerns:
Overall, this is a very high-quality integration that significantly improves the type safety of WordPress core without introducing unnecessary noise or performance regressions. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| - name: Install npm dependencies | ||
| run: npm ci |
There was a problem hiding this comment.
This step is very slow. Running npm ci stalls for a long time at:
🔨 Building Gutenberg for WordPress Core...
Can we cache it?
There was a problem hiding this comment.
Gemini CLI implemented cc01268 with the following reasoning:
To speed up the PHP Static Analysis workflow and prevent it from hanging during the Gutenberg build, I have implemented the following optimizations in
.github/workflows/reusable-php-static-analysis.yml:
- Gutenberg Caching: Added a cache step for the
gutenberg/directory and the.gutenberg-hashfile. The cache key is based on the specific Gutenberg reference defined inpackage.jsonand the content of the Gutenberg build tools. This ensures that Gutenberg is only built once per reference across all CI runs.- Ignored Scripts during
npm ci: Changed the dependency installation step to usenpm ci --ignore-scripts. This prevents the automatic Gutenberg build from triggering during thenpm ciphase, which was the primary cause of the slow runs.- Refined Build Process: The subsequent
npm run build:devstep still ensures all necessary files are present. Because Gutenberg is now cached and the.gutenberg-hashis restored, thegutenberg-synctask becomes a near-instant no-op, while still allowing the core build to complete.These changes will significantly reduce the CI runtime, as the expensive Gutenberg checkout and build (which often takes 5-10 minutes) will be skipped on most runs.
There was a problem hiding this comment.
Also, I was curious if the --ignore-scripts would result in the Gutenberg getting built the first time or after an update:
That is a great observation. You're right that we still need the script to run if the cache is empty or the version changes.
However, because the subsequent step in the workflow is
npm run build:dev, the build is still guaranteed to happen. Here is how it works now:
- Cache Restored: If the cache is valid,
gutenberg/and.gutenberg-hashare restored. Whennpm run build:devruns, it calls thegutenberg-synctask. That task checks.gutenberg-hashagainstpackage.json, sees they match, and returns immediately (taking 0 seconds).- Cache Miss/Invalid: If the cache is empty or the reference changed, the
gutenberg-synctask will see the mismatch and automatically trigger the full checkout and build process (node tools/gutenberg/sync-gutenberg.js), exactly as it did before.By using
--ignore-scriptsduring the rootnpm ci, we simply prevent the build from happening twice or happening at a stage where we haven't yet had a chance to restore the cache. This gives us the best of both worlds: speed when the cache is hot, and correctness when it's not.
There was a problem hiding this comment.
Leaving this open as a good use and disclosure example will resolve once I'm at a desk and can record it
To speed up the workflow and prevent 'npm ci' from hanging during the Gutenberg build: - Added a cache step for the 'gutenberg/' directory and '.gutenberg-hash' file. - Used '--ignore-scripts' during 'npm ci' to bypass the automatic Gutenberg build. - The build remains part of 'npm run build:dev', but now benefits from the restored cache and hash, making it a no-op when the reference hasn't changed. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Thank you robot overlord 🦾🦾🦾
Is this a real concern?
This seems like a nonproblem themes are added to core manually anyway...
I need to check this from a computer 📝
There's an open thread on this already...
I don't remember introducing these changes, I have no indication whether this is legitimate or a hallucination. {the next bunch of lines seemed like it was agreeing with me, thank you 🤖that's why I did it that way...} PS: Important 🚨 Disclaimer (It's here because there's no answer as of yet as to where feedback re the new AI guidelines should be directed). I feel like the above contribution was "workslop". You didn't use AI to make your job as a reviewer easier, you gave me some pointless busywork: a bunch of autogenerated text that I then had to sift through to try and derive meaning or see if there was any value there. Even the few points where it could have been helpful, aren't IRL because I don't know whether you @westonruter, trusted reviewer and committer, vetted the details, or if it's all just probabilistic garbage puked out by a mid-tier model (I don't even know which model was used, what harness...) IMO a "good" use of AI here would have been
Tl;dr proposing the principle of "you own your ai":It's only "helpful" to disclose your LLM usage as a quality signal regarding the level of intentionality in the "work product" (code, code review, human opinion, etc) Everything else is slop. If you contribute it, you "own" it, and if you can't own it yourself, then disclaim it so other folks know the level of signal to give it. |
|
I cited Gemini's review clearly labeled as Gemini's so we could take it as face value. Bottom line is it didn't find any red flags. I used it as a sanity check and I included it here for transparency. |
I made these changes, referenced in #10419 (comment) |
|
@justlevine I also got to the bottom of the issue with |
Co-authored-by: Weston Ruter <westonruter@gmail.com>
|
|
|
…into tests/phpstan/level-0
…into tests/phpstan/level-0
Co-authored-by: Weston Ruter <westonruter@gmail.com>




Trac ticket: https://core.trac.wordpress.org/ticket/61175
This PR adds a PHPStan configuration for PHPStan level 0, along with tests and docs.
Based from #7619 - which remains in use to explore adopting future levels (alongside parallel remediation branches).
Proposal: https://make.wordpress.org/core/2025/07/11/proposal-phpstan-in-the-wordpress-core-development-workflow/
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.